package battleship.data;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;

import battleship.Controller;
import battleship.Loop;
import battleship.PluginEnd;
import battleship.PluginLoop;
import battleship.Setup;
import battleship.data.Scores.SortParameters;
import battleship.player.Player;
import battleship.view.Views;

public class HighScores implements PluginEnd, PluginLoop{
	
	private List<Scores> scores = new LinkedList<Scores>();
	private File files[];
	
	private static final File saveDir = new File("scores");

	@Override
	public void onEnd() {
		loadData();
		saveScores();
	}

	@Override
	public String loopGetFunction() {
		return "highscores";
	}

	@Override
	public String loopGetDescription() {
		return "geeft de momentele highscores";
	}

	@Override
	public String loopGetOptions() {
		return null;
	}
	
	public void sortScores()
	{
		Collections.sort(scores, Scores.getComparator(SortParameters.WINS));
	}

	@Override
	public int loopExecFunction(String[] arguments, Player player) {
		switch (Controller.getGUI())
		{
		case Console:
			loadData();
			sortScores();
			
			
			int maxlength = 5; //length of namen

			//get the max name length
			for(Scores score : scores)
			{
				if(score.getName().length() > maxlength) maxlength = score.getName().length();
			}

			for(int length = 0;
			length < " | gewonnen".length() + " | verloren |".length() + maxlength + 3;
			++length)
			{
				System.out.printf("-");
			}
			System.out.println();

			//print the header
			System.out.printf("| %s ", "namen");
			for(int length = 0; length < maxlength - "namen".length(); ++length) 
				System.out.printf(" ");
			System.out.printf(" | gewonnen");
			System.out.printf(" | verloren |\n");
			//print separator
			for(int length = 0;
			length < " | gewonnen".length() + " | verloren |".length() + maxlength + 3;
			++length)
			{
				System.out.printf("-");
			}
			System.out.println();

			//print the players data in a for loop, very similar to the past loop
			for(Scores score : scores)
			{
				System.out.printf("| %s", score.getName());
				for(int length = 0; length <= maxlength - score.getName().length(); ++length)
				{
					System.out.printf(" ");
				}
				System.out.printf(" | %8d | %8d |\n", score.getWins(), score.getLosses());
			}

			for(int length = 0;
			length < " | gewonnen".length() + " | verloren |".length() + maxlength + 3;
			++length)
			{
				System.out.printf("-");
			}

			break;
		case GUI:
			loadData();
			sortScores();
			
			final JFrame window = new JFrame("highscores");
			window.setLayout(new BorderLayout(5,5));
			JPanel okButton = new JPanel(new FlowLayout());
			JButton ok = new JButton("Ok");
			
			ok.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent e) {
					window.dispose();
					
				}
			});
			
			okButton.add(ok);
			
			window.add(okButton, BorderLayout.SOUTH);
			
			String[] columnNames = new String[] {
					"namen",
					"gewonnen",
					"verloren",
			};
			
			Object[][] values = new Object[scores.size()][3];
			
			for(int score = 0; score < scores.size(); ++score)
			{
				values[score] = new Object[] {
						scores.get(score).getName(),
						scores.get(score).getWins(),
						scores.get(score).getLosses(),
				};
			}
			
			JTable data = new JTable(values, columnNames);
			data.setEnabled(false);
			window.add(data);
			
			window.setLocation(600, 300);
			window.pack();
			window.setVisible(true);
		
			break;
		}
		return 0;
	}

	@Override
	public boolean loopErrorHandler(int error) {
		//no errors to handle
		return false;
	}

	@Override
	public boolean acceptArguments() {
		return false;
	}

	@Override
	public Views[] loopSupportedViews() {
		return new Views[] {Views.Console, Views.GUI};
	}
	
	/**
	 * loads updated data from the game, if the game has a winner it will automatically save
	 * the results.
	 */
	public void loadData()
	{
		loadSubDir();
		
		// no need to reload when game hasn't even finished yet
		if(!Loop.getWin())
		{
			// this will be the first time the players will be loaded
			if(scores.size() == 0)
			{
				parseFiles();
				checkCurrentPlayers();
			}
		}
		else
		{
			parseFiles();
			checkCurrentPlayers();
			Player winner = getWinner();
			Player loser = Setup.getPlayer2(winner);
			
			for(Scores score : scores)
			{
				if(score.getName().equals(winner.getName())) score.increaseWins();
				
				if(score.getName().equals(loser.getName())) score.increaseLosses();
			}
		}
	}
	
	/**
	 * loads the files within the scores directory if they weren't already loaded
	 */
	public void loadSubDir()
	{
		if (files == null)
		{
			files = saveDir.listFiles();
		}
	}
	
	public void makeNewPlayer(Player newPlayer)
	{
		scores.add(new Scores(newPlayer.getName(), 0, 0));
	}
	
	/**
	 * checks for the current players in game and creates new scores object for them if
	 * they don't have one yet
	 */
	public void checkCurrentPlayers()
	{
		boolean firstPlayer = false;
		boolean secondPlayer = false;
		if(scores.size() == 0)
		{
			for(Scores score : scores)
			{
				if(score.getName().equals(Setup.getPlayers()[0])) firstPlayer = true; break;
			}

			for(Scores score : scores)
			{
				if(score.getName().equals(Setup.getPlayers()[1])) secondPlayer = true; break;
			}
		}
		
		if(!firstPlayer) makeNewPlayer(Setup.getPlayers()[0]);
		if(!secondPlayer) makeNewPlayer(Setup.getPlayers()[1]);
	}
	
	public void parseFiles()
	{
		if (files != null)
		{
			for(int file = 0; file < files.length; ++file)
			{
				try {
					
					// ignore .svn and .git vcs directories
					if (files[file].getName().equals(".svn")
							|| files[file].getName().equals(".git")) continue;
					DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
					DocumentBuilder db;

					db = dbf.newDocumentBuilder(); 
					Document doc = db.parse(files[file]);

					//retrieve name
					String name = doc.getElementsByTagName("name").item(0).getTextContent();
					//retrieve wins
					String wins = doc.getElementsByTagName("wins").item(0).getTextContent();
					//retrieve losses
					String losses = doc.getElementsByTagName("losses").item(0).getTextContent();

					scores.add(new Scores(name,
							Integer.valueOf(wins),
							Integer.valueOf(losses)));

				} catch (Exception e) {
					System.err.println("Fout met het inlezen van het bestand: "
							+ files[file].getName());
					System.err.println("Het bestand zal nu verwijderd worden");

					//TODO uncomment after done debugging
					//files[file].delete();
				}
			}
		}
	}
	
	public void saveScores()
	{
		for (Scores score : scores)
		{
			score.toSave();
		}
	}
	
	public Player getWinner()
	{
		if (!Loop.getWin()) return null;
		
		for(int player = 0; player < Setup.getPlayers().length; ++player)
		{
			if(Loop.getWin(Setup.getPlayers()[player])) return Setup.getPlayers()[player];
		}
		
		return null;
	}
}
